/**
 * FS 模块的测试
 */

const fs = require('fs');
const path = require('path');
/**
 * 实现文件拷贝
 */
function copyFile() {
    fs.readFile(path.resolve(__dirname, './a.txt'), (error, data) => {
        if (error) {
            throw error;
        } else {
            //copy file 
            console.log('data', data);
            //覆盖写入
            fs.writeFileSync(path.resolve(__dirname, './acopy.txt'), data);
            //追加写入
            fs.appendFileSync(path.resolve(__dirname, './acopy.txt'), data);
        }
    })
};
copyFile();


/**
 * 📁文件夹创建
 * 正确的递归创建
 */
function createDirRight(dirPath) {
    //将目标路径进行拆分
    let array = dirPath.split('/');
    for (let i = 0; i < array.length; i++) {
        let tempPath = array.slice(0, i + 1).join('/');
        try {
            //判断是不是存在了，不存在就报错
            fs.accessSync(tempPath)
        } catch (e) {
            fs.mkdirSync(tempPath);
        }
    }
}
/**
 * 错误的创建方式
 * @param {目标路径} dirPath 
 */
function createDirWrong(dirPath) {
    try {
        fs.accessSync(dirPath);
    } catch (e) {
        fs.mkdir(path.resolve(__dirname, dirPath), (err) => {
            throw new Error(err);
        });
    }
}
// 自执行函数
// ((params) => {
//     createDirWrong('a');
//     try {
//         createDirWrong('a/b/c');
//     } catch (e) {
//         createDirRight('a/b/c');
//     }
// })();

/**
 * 文件的递归删除（深度优先删除）
 * 深度优先就是不停的向下递归查找，是文件就删除，是目录就递归
 */
function DeepRmDirs(p) {
    let stateObj = fs.statSync(p);
    //如果是文件就列出文件递归删除
    if (stateObj.isDirectory()) {
        let fileDirs = fs.readdirSync(p);
        console.log(fileDirs);
        //将列出的文件，全部拼接上父级目录
        fileDirs = fileDirs.map(item => { path.join(p, item) })
        fileDirs.forEach(item => {
            DeepRmDirs(item);
        })
        //删除当前目录
        fs.rmdirSync(p);
    } else {
        //是文件就直接删除
        fs.unlinkSync(p);
    }
}
// DeepRmDirs('a');

/**
 * 文件的递归删除（广度优先）
 * 广度优先的想法是：一层一层的看，然后将所有的目录存放在数组中。
 * 然后将数组中的目录从后向前删除。
 */
function WildRmDirs(p) {
    let arr = [p];
    let index = 0;
    let current;
    while (current = arr[index++]) {
        //看看是文件还是目录
        let stateObj = fs.statSync(current);
        if (stateObj.isDirectory) {
            //文件夹就列出下面的文件夹和文件
            let targetDir = fs.readdirSync(current);
            // 拼接父级目录
            targetDir = targetDir.map(dir => path.join(current, dir));
            arr = [...arr, ...targetDir];
        }
    }
    // 删除目录
    for (let i = arr.length - 1; i >= 0; i--) {
        const item = arr[i];
        let state = fs.statSync(item);
        if (state.isDirectory()) {
            fs.rmdirSync(item)
        } else {
            fs.unlinkSync(item);
        }
    }
}

// 文件读取
// 因为fs.readFile太过暴力，会把整个文件读到内存中，所以不适合大文件。
// 大文件，我们用fs.open方法来指定每次读多少到内存中，所以也就可以实现读一点写一点
let buf = Buffer.alloc(6);//分配6个字节
// 文件权限：读    写    执行
//        r（4） w（2） x（1）
fs.open(path.join(__dirname, './acopy.txt'), 'r', (err, fd) => {
    console.log('fd', fd);//fd文件描述符--指向文件
    /**
     * buf 要写入的内存
     * 0 从buf的第几个位置
     * 5 往buf中写入多少字节
     * 0 从文件什么位置开始读取
     */
    fs.read(fd, buf, 0, 5, 0, (err, bytesRead) => {
        console.log(bytesRead);
        console.log(buf.toString());
    })
})


// 写文件
// let bufStr = Buffer.from('爱学习爱劳动');
// fs.open(path.join(__dirname, './acopy.txt'), 'w', (err, fd) => {
//     fs.write(fd, bufStr, 9, 3, 0, (err, written) => {
//         console.log(written);
//     })
// })


// 文件的复制操作
const SIZE = 3;
// cache area 
let copyBuffer = Buffer.alloc(SIZE);
// start position
let readOffset = 0;
// open file
fs.open(path.join(__dirname, './a.txt'), 'r', (err, fd) => {
    // open anather file 
    fs.open(path.join(__dirname, 'copyFile.txt'), 'w', (err, wfd) => {
        function next(){
            // read file
            fs.read(fd, copyBuffer, 0, SIZE, readOffset, (err, bytesRead) => {
                if(bytesRead == 0){
                    // finished read file,close all files;
                    fs.close(fd,()=>{console.log('this call back could be empty');})
                    fs.close(wfd,()=>{console.log('this call back could be empty');})
                    return;
                }
                // 这里是+= bytesRead 而不是size。因为如果最后一次不足size，那么会有上一次的缓存，也就是会多写一些东西
                readOffset += bytesRead;
                // write file
                fs.write(wfd, copyBuffer, 0, bytesRead, (err, buffer) => {
                    // continue read 
                    next();
                })
            })
        }

        next();
    })
})
